import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { AppConfig } from '../../config';
import { WebSocketService } from './websocket.service';
import { IPush } from './ipush.interface';
import { TagProtocol, TagType } from './tag-protocol';
import { Subject } from 'rxjs/Subject';
import { MatrixData } from '../../entity/matrix-data';
import { TagData } from '../../entity/tag-data.model';
import { FaultData } from '../../entity/fault-data';
import { Session } from './session';
import { SubstationData } from '../../entity/substation-data';
/**
 * 即时通信传送推服务（Instant Messaging）
 *
 * @export
 * @class IMPushService
 */
@Injectable()
export class IMPushTestService implements IPush {
  /**
     * 时间格式化字符串
     *
     * @private
     * @type {string}
     * @memberof IMPushTestService
     */
  private fomat: string = 'yyyy-MM-dd HH:mm:ss';
  /**
    * websocket通信地址
    *
    * @private
    * @type {string}
    * @memberof IMPushService
    */
  private get url(): string {
    return AppConfig.APP_WEBSOCKET;
  }


  /**
   * 服务ws集合
   *
   * @private
   * @type {session[]}
   * @memberof IMPushService
   */
  private WebSockets: WebSocket[] = [];

  /**
   * 服务session集合
   *
   * @private
   * @type {session[]}
   * @memberof IMPushService
   */
  private sessionMap: Session[] = [];

  /**
   * Creates an instance of IMPushService.
   * @memberof IMPushService
   */
  constructor() {
    let self = this;
    //监听窗口关闭事件，当窗口关闭时，主动去关闭websocket连接，防止连接还没断开就关闭窗口，server端会抛异常。
    window.onbeforeunload = function () {
      self.close();
    }
  }
  /**
   * 开始订阅测点实时数据
   * (首先返回测点快照值，其后服务端开启数据订阅，数据变化时推送到客户端)
   *
   * @returns {Subject<any>}
   * @memberof IMPushService
   */
  public begin(protocol: TagProtocol): Subject<TagData[]> {
    // 隐藏字段
    protocol.setDefineProperty();
    Object.defineProperty(protocol, 'endTime', { enumerable: false });
    Object.defineProperty(protocol, 'startTime', { enumerable: false });
    Object.defineProperty(protocol, 'historyInterval', { enumerable: false });
    Object.defineProperty(protocol, 'pushInterval', { enumerable: false });
    return this.common(`${this.url}/realtimeServer`, protocol);
  }

  public interval(protocol: TagProtocol, interval: number): Subject<TagData[]> {
    // 隐藏字段
    protocol.setDefineProperty();
    Object.defineProperty(protocol, 'endTime', { enumerable: false });
    Object.defineProperty(protocol, 'startTime', { enumerable: false });
    Object.defineProperty(protocol, 'historyInterval', { enumerable: false });
    Object.defineProperty(protocol, 'pushInterval', { enumerable: true });
    return this.common(`${this.url}/realtimeServer`, protocol);
  }

  public withHistories(protocol: TagProtocol, start: Date, end: Date): Subject<any>;
  public withHistories(protocol: TagProtocol, start: Date, end: Date, interval: number): Subject<any>;
  public withHistories(protocol: TagProtocol, start: Date, end: Date, interval: { history: number; push: number; }): Subject<any>;
  public withHistories(protocol: TagProtocol, start: Date, end: Date, interval?: any): Subject<any> {
    protocol.startTime = start;
    protocol.endTime = end;
    if (interval != null) {
      if (typeof interval == 'number') {
        protocol.historyInterval = interval;
        protocol.setDefineProperty();
        Object.defineProperty(protocol, 'pushInterval', { enumerable: false });
        Object.defineProperty(protocol, 'historyInterval', { enumerable: true });
        return this.common(`${this.url}/realtimeServer`, protocol);
      } else if (typeof interval == 'object') {
        protocol.pushInterval = interval.push;
        protocol.historyInterval = interval.history;
        protocol.setDefineProperty();
        Object.defineProperty(protocol, 'historyInterval', { enumerable: true });
        Object.defineProperty(protocol, 'pushInterval', { enumerable: true });
        return this.common(`${this.url}/realtimeServer`, protocol);
      }
    } else {
      protocol.setDefineProperty();
      Object.defineProperty(protocol, 'historyInterval', { enumerable: false });
      Object.defineProperty(protocol, 'pushInterval', { enumerable: false });
      return this.common(`${this.url}/realtimeServer`, protocol);
    }

  }

  /**
   * 公共的WebSocket调用方法
   *
   * @private
   * @param {string} url
   * @param {string} session
   * @param {*} sendData
   * @returns {Subject<any>}
   * @memberof IMPushService
   */
  private common(url: string, sendData: any): Subject<any> {
    let subject = new Subject<any>();
    // 用于发送点名
    const sendSocket = new WebSocketService(url);
    sendSocket.onError((ev: Event) => {
      // console.log('IMPushService (sendSocket) onError', ev);
    });
    sendSocket.onClose((ev: CloseEvent) => {
      //console.log('IMPushService (sendSocket) onClose', ev.code);
      // 关闭订阅
      subject.unsubscribe();
      subject = null;
    });
    sendSocket.onOpen((ev: Event) => {

      //console.log('IMPushService (sendSocket) onOpen', sendData);
      let respondSelf: WebSocket = ev.currentTarget as WebSocket;
      if (sendData != null) {

        respondSelf.send(JSON.stringify(sendData));
      }
      this.WebSockets.push(respondSelf);
    });
    sendSocket.onMessage((msg: MessageEvent) => {
      const data = JSON.parse(msg.data);
      if (data) {
        if (subject != null && !subject.closed && !subject.isStopped) {
          const obj: Object = data[0];
          if (!data.length) {
            subject.next(data);
          } else if (data.hasOwnProperty('segment')) {
            const segment: { segment: number } = data;
            subject.next(segment);
          } else if (obj.hasOwnProperty('faultCode')) {
            const faultDatas: FaultData[] = data;
            subject.next(faultDatas);
          } else if (obj.hasOwnProperty('stateId')) {
            const matrixDatas: MatrixData[] = data;
            subject.next(matrixDatas);
          } else if (obj.hasOwnProperty('stationTagCode')) {
            const substationData: SubstationData[] = data;
            subject.next(substationData);
          } else if (obj.hasOwnProperty('code')) {
            const tagDatas: TagData[] = data;
            subject.next(tagDatas);
          }

        }
      }
    });
    return subject;
  }


  /**
   * 订阅风机矩阵数据
   *
   * @param {{tagId: number,farmIds: number[]}} matrix
   * @returns {Subject<any>}
   * @memberof IMPushService
   */
  public matrix(matrix: { tagId: number, farmIds: number[] }): Subject<MatrixData[]> {
    return this.common(`${this.url}/matrixServer`, [matrix]);
  }

  /**
   * 订阅风机报警数据
   *
   * @param {number} userId
   * @returns {Subject<FaultData[]>}
   * @memberof IMPushService
   */
  public alarm(userId: number): Subject<FaultData[]> {
    //return this.common(`ws://123.207.167.163:9010/ajaxchattest`, userId);
    return this.common(`${this.url}/alarmServer`, userId);
  }

  /**
   * 订阅升压站数据
   *
   * @param {number} userId
   * @returns {Subject<SubstationData[]>}
   * @memberof IMPushService
   */
  public substation(userId: number): Subject<SubstationData[]> {
    return this.common(`${this.url}/stationServer`, userId);
  }
  /**
   *开始订阅历史报警数据
   *
   * @param {number[]} farmIds
   * @returns {Subject<FaultData[]>}
   * @memberof IMPushTestService
   */
  public alarmHistory(startTime, endTime, deviceIds: number[]): Subject<FaultData[]> {
    const tagArrary = deviceIds.map(d => d.toString());
    return this.common(`${this.url}/historyAlarmServer`, { startTime: startTime, endTime: endTime, tagArrary: tagArrary });
  }
  /**
   * 关闭
   *
   * @memberof IMPushService
   */
  public close() {
    this.WebSockets.forEach(ws => {
      if (ws.readyState === 1)
        ws.close();
    });

    this.sessionMap.forEach(session => {
      //如果通道没关闭
      if (session.socket.socket.readyState === 1) {
        let closeSocket = new WebSocketService(`${this.url}/${session.closeServerChannelName}`);
        closeSocket.onOpen((ev: Event) => {
          ///console.log('(closeSocket) onOpen', ev);
          let selfCloseWebSocket = ev.currentTarget as WebSocket;
          //发送关闭指令
          selfCloseWebSocket.send(`${session.serverChannelName},${session.sessionId},${session.stopCommand}`);
        });
        closeSocket.onMessage((ev: MessageEvent) => {
          /// console.log('(closeSocket) onMessage', ev.data);
          let selfCloseWebSocket = ev.currentTarget as WebSocket;

          selfCloseWebSocket.close();
          //强制关闭
          if (session.socket.socket.readyState == 1) {
            session.socket.socket.close();
          }
        });
        closeSocket.onClose((ev: CloseEvent) => {
          ///console.log('(closeSocket) onClose', ev.code);

        });
        closeSocket.onError((ev: Event) => {
          ///console.log('(closeSocket) onError', ev);
        });
      }
    });
  }
}



// WEBPACK FOOTER //
// ./src/app/service/data-source/impush-test.service.ts